var __createBinding =
    (this && this.__createBinding) ||
    (Object.create
        ? (o, m, k, k2) => {
              if (k2 === undefined) k2 = k;
              var desc = Object.getOwnPropertyDescriptor(m, k);
              if (
                  !desc ||
                  ("get" in desc
                      ? !m.__esModule
                      : desc.writable || desc.configurable)
              ) {
                  desc = { enumerable: true, get: () => m[k] };
              }
              Object.defineProperty(o, k2, desc);
          }
        : (o, m, k, k2) => {
              if (k2 === undefined) k2 = k;
              o[k2] = m[k];
          });
var __setModuleDefault =
    (this && this.__setModuleDefault) ||
    (Object.create
        ? (o, v) => {
              Object.defineProperty(o, "default", {
                  enumerable: true,
                  value: v,
              });
          }
        : (o, v) => {
              o.default = v;
          });
var __importStar =
    (this && this.__importStar) ||
    ((mod) => {
        if (mod?.__esModule) return mod;
        var result = {};
        if (mod != null)
            for (var k in mod)
                if (k !== "default" && Object.hasOwn(mod, k))
                    __createBinding(result, mod, k);
        __setModuleDefault(result, mod);
        return result;
    });
var __importDefault =
    (this && this.__importDefault) ||
    ((mod) => (mod?.__esModule ? mod : { default: mod }));
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnusedVariableRemover = void 0;
const t = __importStar(require("@babel/types"));
const traverse_1 = __importDefault(require("@babel/traverse"));
const transformation_1 = require("../transformation");
class UnusedVariableRemover extends transformation_1.Transformation {
    /**
     * Executes the transformation.
     * @param log The log function.
     */
    execute(_log) {
        const self = this;
        (0, traverse_1.default)(this.ast, {
            Scope(path) {
                for (const binding of Object.values(path.scope.bindings)) {
                    if (
                        !binding.referenced &&
                        binding.constantViolations.length === 0 &&
                        binding.path.key !== "handler" &&
                        !binding.path.isFunctionExpression() // don't remove named function expressions
                    ) {
                        // ensure we don't remove variables that are exposed globally
                        if (
                            t.isProgram(binding.scope.block) &&
                            (binding.kind === "var" ||
                                binding.kind === "hoisted")
                        ) {
                            return;
                        }
                        const paths =
                            binding.path.parentKey === "params"
                                ? [
                                      ...binding.referencePaths,
                                      ...binding.constantViolations,
                                  ]
                                : [
                                      binding.path,
                                      ...binding.referencePaths,
                                      ...binding.constantViolations,
                                  ];
                        for (const path of paths) {
                            if (
                                path.key === "consequent" ||
                                path.key === "alternate" ||
                                path.key === "body"
                            ) {
                                path.replaceWith(t.blockStatement([]));
                            } else {
                                // check if we are going to create an empty variable declaration (otherwise can sometimes trigger Babel build error)
                                const parentPath = path.parentPath;
                                if (
                                    parentPath?.isVariableDeclaration() &&
                                    parentPath.node.declarations.length === 1
                                ) {
                                    parentPath.remove();
                                } else {
                                    path.remove();
                                }
                            }
                            if (paths.length > 0) {
                                self.setChanged();
                            }
                        }
                    }
                }
            },
        });
        return this.hasChanged();
    }
}
exports.UnusedVariableRemover = UnusedVariableRemover;
UnusedVariableRemover.properties = {
    key: "unusedVariableRemoval",
    rebuildScopeTree: true,
};
